package com.zxd.interview.conrruentbook;

import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 尝试使用Lock锁解决死锁问题
 * @author Xander
 * @version v1.0.0
 * @Package : com.zxd.interview.conrruentbook
 * @Description : TryLockDeadLock
 * @Create on : 2023/5/10 10:53
 **/
public class TryLockDeadLock implements Runnable{

    private static final Lock LOCK1 = new ReentrantLock();
    private static final Lock LOCK2 = new ReentrantLock();
    int flag = 1;

    @Override
    public void run() {
            thread1Work();

    }

    /**
     * 线程1工作流程
     * @description 线程1工作流程
     * @param
     * @return
     * @author Xander
     * @date 2023/5/12 16:58
     */
    private void thread1Work() {
        for (int i = 0; i < 100; i++) {
            // 第一把锁进入，尝试获取锁1
            if (1 == flag) {
                try {
                    if (LOCK1.tryLock(800, TimeUnit.MILLISECONDS)) {
                        try {
                            System.out.println(Thread.currentThread().getName() + "线程1获取到锁1");
                            TimeUnit.MILLISECONDS.sleep(1);
                            // 获取到第一把锁之后，开始获取第二把锁

                            if (LOCK2.tryLock(800, TimeUnit.MILLISECONDS)) {
                                try {
                                    System.out.println(Thread.currentThread().getName() + "线程1获取到锁2");
                                break;
                                } finally {
                                    LOCK2.unlock();
                                }
                            } else {
                                // 线程1 此时获取锁失败
                                System.out.println(Thread.currentThread().getName() + "线程1获取锁2失败，已重试");
                            }
                        } finally {
                            LOCK1.unlock();
                            TimeUnit.NANOSECONDS.sleep(new Random().nextInt(100));
                        }
                    }
                } catch (InterruptedException e) {

                }
            } else {
                // 线程1 此时获取锁失败
                System.out.println(Thread.currentThread().getName() + "线程1获取锁1失败，已重试");
            }

            // 第二个线程进入，尝试获取锁2
            if (0 == flag) {
                try {
                    if (LOCK2.tryLock(800, TimeUnit.MILLISECONDS)) {
                        try {
                            System.out.println(Thread.currentThread().getName() + "线程2获取到锁2");
                            TimeUnit.MILLISECONDS.sleep(1);
                            // 获取到第一把锁之后，开始获取第二把锁

                                if (LOCK1.tryLock(800, TimeUnit.MILLISECONDS)) {
                                    try {
                                        System.out.println(Thread.currentThread().getName() + "线程2获取到锁2");
                                        break;
                                    } finally {
                                        LOCK1.unlock();
                                    }
                                } else {
                                    // 线程1 此时获取锁失败
                                    System.out.println(Thread.currentThread().getName() + "线程2获取锁2失败，已重试");
                                }


                        } finally {
                            LOCK2.unlock();
                            TimeUnit.NANOSECONDS.sleep(new Random().nextInt(100));
                        }
                    }
                } catch (InterruptedException e) {

                }
            } else {
                // 线程2 此时获取锁失败
                System.out.println(Thread.currentThread().getName() + "线程2获取锁2失败，已重试");
            }
        }
    }

    public static void main(String[] args) {
        TryLockDeadLock tryLockDeadLock1 = new TryLockDeadLock();
        TryLockDeadLock tryLockDeadLock2 = new TryLockDeadLock();
        tryLockDeadLock1.flag = 1;
        tryLockDeadLock2.flag = 0;
        new Thread(tryLockDeadLock1).start();
        new Thread(tryLockDeadLock2).start();

    }/*
    结果，虽然两个线程会不断的争抢着两把锁，但是最终会有一放谦让另一方
    Thread-0线程1获取到锁1
    Thread-1线程1获取锁1失败，已重试
    Thread-1线程2获取到锁2
    Thread-0线程1获取锁2失败，已重试
    Thread-1线程2获取锁2失败，已重试
    Thread-1线程1获取锁1失败，已重试
    Thread-1线程2获取到锁2
    Thread-0线程2获取锁2失败，已重试
    Thread-0线程1获取到锁1
    Thread-0线程1获取锁2失败，已重试
    Thread-1线程2获取锁2失败，已重试
    Thread-1线程1获取锁1失败，已重试
    Thread-0线程2获取锁2失败，已重试
    Thread-1线程2获取到锁2
    Thread-0线程1获取到锁1
    Thread-0线程1获取锁2失败，已重试
    Thread-1线程2获取锁2失败，已重试
    Thread-1线程1获取锁1失败，已重试
    Thread-0线程2获取锁2失败，已重试
    Thread-1线程2获取到锁2
    Thread-0线程1获取到锁1
    Thread-0线程1获取锁2失败，已重试
    Thread-1线程2获取锁2失败，已重试
    Thread-0线程2获取锁2失败，已重试
    Thread-1线程1获取锁1失败，已重试
    Thread-0线程1获取到锁1
    Thread-1线程2获取到锁2
    Thread-0线程1获取锁2失败，已重试
    Thread-1线程2获取锁2失败，已重试
    Thread-0线程2获取锁2失败，已重试
    Thread-0线程1获取到锁1
    Thread-1线程1获取锁1失败，已重试
    Thread-1线程2获取到锁2
    Thread-0线程1获取锁2失败，已重试
    Thread-1线程2获取到锁2
    Thread-0线程2获取锁2失败，已重试
    Thread-0线程1获取到锁1
    Thread-0线程1获取到锁2

    Process finished with exit code 0

    */
}
